package com.xneure.function;

import java.util.ArrayList;
import java.util.List;
import com.xneure.function.enums.TokenType;
import com.xneure.function.node.Token;
import com.xneure.function.processor.TokenProcessor;
import com.xneure.utils.ObjectUtil;

public class SyntaxAnalyze {
	private List<Token> tokens = new ArrayList<Token>(20);
	private TokenProcessor processor = new TokenProcessor() {
		@Override
		public void processor(Token currToken, Token beforeToken) {
		}
	};

	public void setProcessor(TokenProcessor processor) {
		this.processor = processor;
	}

	public void analyze(String data) {
		char[] temData = data.toCharArray();
		StringBuilder cb = new StringBuilder(1024);
		int col = 1, line = 1;
		processor.start();
		TokenType formTokenType;
		for (int i = 0; i < temData.length; i++) {
			switch (temData[i]) {
			case ',':
				col = createToken(temData, cb, col, line, i, TokenType.DOT);
				break;
			case '(':
			case ')':
			case '+':
			case '-':
			case '*':
			case '/':
				formTokenType = isKeyword(cb.toString().trim(), temData[i]);
				if (formTokenType != TokenType.UNKNOWN) {
					col = createToken(temData, cb, col, line, i, formTokenType);
				} else {
					cb.append(temData[i]);
				}
				break;
			case 10:
			case 13:
				int c = 1;
				if (temData[i + 1] == 10 || temData[i + 1] == 13) {
					++i;
					c = 1;
				} else {
					c = i + 1;
				}
				createToken(cb.toString(), col, line, i, TokenType.formTokenType(cb.toString()));
				line++;
				col = c;
				cb.delete(0, cb.length());
				break;
			default:
				cb.append(temData[i]);
				break;
			}
		}
		processor.end();
	}

	private int createToken(char[] temData, StringBuilder cb, int col, int line, int i, TokenType tt) {
		if (tt.ordinal() > TokenType.KEYWORD.ordinal()) {
			if (tt == TokenType.LEFT_BRACKETS && cb.length() > 0) {
				createToken(cb.toString().trim(), col, line, i, TokenType.FUNCTION);
			} else {
				if (tt.ordinal() > TokenType.RIGHT_BRACKETS.ordinal()) {
					createToken(cb.toString().trim(), col, line, i, tt);
					tt = TokenType.FUNCTION;
				} else {
					if (tt != TokenType.LEFT_BRACKETS) {
						createToken(cb.toString().trim(), col, line, i, TokenType.VALUE);
					}
				}
			}
		} else {
			createToken(cb.toString().trim(), col, line, i, TokenType.VALUE);
		}
		createToken(String.valueOf(temData[i]), i, line, i, tt);
		cb.delete(0, cb.length());
		return i + 1;
	}

	private TokenType isKeyword(String sb, char temData) {
		TokenType tt;
		if (sb.length() == 3) {
			tt = TokenType.formTokenType(sb.toString());
			if (tt == TokenType.UNKNOWN) {
				tt = TokenType.formTokenType(String.valueOf(temData));
			}
		} else {
			tt = TokenType.formTokenType(String.valueOf(temData));
		}
		if (tt != null && sb.startsWith("\"") && sb.endsWith("\"")) {
			return TokenType.UNKNOWN;
		} else {
			return tt;
		}
	}

	private void createToken(String data, int col, int line, int i, TokenType tt) {
		if (ObjectUtil.isNull(data)) {
			return;
		}
		Token temToken = new Token();
		temToken.beginPoint = col;
		temToken.endPoint = i;
		temToken.line = line;
		temToken.data = data;
		temToken.type = tt;
		if (tokens.size() > 1) {
			processor.processor(temToken, tokens.get(tokens.size() - 1));
		} else {
			processor.processor(temToken, null);
		}
		tokens.add(temToken);
	}

	public Token[] getToken() {
		return tokens.toArray(new Token[tokens.size()]);
	}

	public void clear() {
		tokens.clear();
	}
}
